package top.eggcode.setup.config.shiro;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.TimeoutUtils;
import top.eggcode.common.cache.RedisUnit;
import top.eggcode.common.error.ApplicationException;

import java.io.*;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

public class RedisSessionStore extends AbstractSessionDAO {

    private static Logger logger = LoggerFactory.getLogger(RedisSessionStore.class);

    /**
     * 数据key前缀
     */
    private final String KEY_PREFIX = "web:session:";

    private static final int DEFAULT_EXPIRE_TIME = 1800000;

    private RedisUnit buffer;

    public RedisSessionStore(RedisUnit buffer) {
        this.buffer = buffer;
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        this.storeToByte(session);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        Session session = this.readByByte(sessionId);
        if (session == null) {
            throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
        } else {
            return session;
        }


    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        this.storeToByte(session);
    }

    @Override
    public void delete(Session session) {
        buffer.del(KEY_PREFIX + session.getId());
    }

    @Override
    public Collection<Session> getActiveSessions() {
        return null;
    }

    protected Session readByByte(Serializable sessionId) {
        byte[] objectByte = buffer.getByte(KEY_PREFIX + sessionId);
        if (objectByte == null) {
            return null;
        }
        try {
            SimpleSession session = (SimpleSession) new ObjectInputStream(new ByteArrayInputStream(objectByte)).readObject();
            return session;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            throw new ApplicationException("byte 转 SimpleSession 失败");
        }
    }

    protected void storeToByte(Session session) {
        SimpleSession sourceSession = (SimpleSession) session;
        ByteArrayOutputStream serialized = new ByteArrayOutputStream();
        byte[] sessionByte = null;
        ObjectOutputStream serializer = null;
        try {
            serializer = new ObjectOutputStream(serialized);
            serializer.writeObject(sourceSession);
            serializer.close();
            sessionByte = serialized.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw new ApplicationException("Session 转换字节失败");
        }

        buffer.setByte(KEY_PREFIX + session.getId(), sessionByte);
        buffer.expire(KEY_PREFIX + session.getId(), TimeoutUtils.toSeconds(session.getTimeout(), TimeUnit.MILLISECONDS));
    }
}
